//for phy SMI interface 
module	mdio_ctrl(
	input	wire		sclk,
	input	wire		rst_n,
	
	output	wire		mdc,
	inout	tri		mdio,
	
	input	wire		w_en,
	input	wire	[4:0]	phy_addr,
	input	wire	[4:0]	reg_addr,
	input	wire	[15:0]	w_data,
	
	//loop read phy config register
	output	wire	[4:0]	conf_addr,
	output	wire	[15:0]	conf_data,
	
	output	reg		wr_busy
);

parameter	IDLE	=3'b000;
parameter	READ	=3'b001;
parameter	WRITE	=3'b010;
parameter	WAIT	=3'b100;

parameter	PHYADDR	=5'b00000;

reg	[15:0]	buf_32	[31:0];

wire		busy;
wire		r_flag;
wire		w_flag;
wire		r_dv;
wire	[15:0]	r_data;
reg		r_dv_t;

reg	[2:0]	state/* synthesis syn_keep=1 xc_props="X" */;
reg		req_w_en;
reg	[4:0]	w_phy_addr;
reg	[4:0]	w_reg_addr;
reg	[15:0]	w_data_r;
reg	[4:0]	r_cnt;
reg	[4:0]	r_phyaddr;
reg	[4:0]	mdio_phy_addr;
reg	[4:0]	mdio_reg_addr;
reg	[15:0]	mdio_w_data;

reg	[4:0]	w_buf_addr;
reg		w_buf_en;
wire	[15:0]	w_buf_data;

reg	[4:0]	r_buf_addr;
reg	[4:0]	r_buf_addr_t;
reg	[4:0]	r_buf_addr_tt;
reg	[15:0]	r_buf_data;
reg	[15:0]	dout;
always @(posedge sclk)
	if(!rst_n)
		state<=IDLE;
	else case(state)
		IDLE:state<=WAIT;
		WAIT:if(req_w_en && busy=='d0)
			state<=WRITE;
		     else if(busy=='d0)
		     	state<=READ;
		READ:state<=WAIT;
		WRITE:state<=WAIT;
		default:state<=IDLE;
	endcase

always @(posedge sclk)
	if(w_en)
		req_w_en<='d1;
	else if(state[1]=='d1)
		req_w_en<='d0;
always @(posedge sclk)
	if(w_en)begin
		w_phy_addr<=phy_addr;
		w_reg_addr<=reg_addr;
		w_data_r<=w_data;
	end
assign	r_flag=state[0];

always @(posedge sclk)
	if(r_flag)
		r_cnt<=r_cnt+'d1;
assign	w_flag=state[1];

always @(posedge sclk)
	r_phyaddr<=PHYADDR;		

always @*
	if(r_flag)begin
		mdio_phy_addr<=r_phyaddr;
		mdio_reg_addr<=r_cnt;
	end
	else if(w_flag)begin
		mdio_phy_addr<=w_phy_addr;
		mdio_reg_addr<=w_reg_addr;
		mdio_w_data<=w_data_r;
	end else begin
		mdio_phy_addr<='d0;
		mdio_reg_addr<='d0;
		mdio_w_data<='d0;
	end

always @(posedge sclk)
	r_dv_t<=r_dv;

always @*
	if(r_dv_t=='d0 && r_dv=='d1)
		w_buf_en<='d1;
	else 
		w_buf_en<='d0;

always @(posedge sclk)
	if(w_buf_en)
		w_buf_addr<=w_buf_addr+'d1;

assign	w_buf_data=r_data;
always @(posedge sclk)
	if(w_buf_en)
		buf_32[w_buf_addr]<=w_buf_data;

always @(posedge sclk)
	r_buf_data<=buf_32[r_buf_addr];
	
assign	conf_data=r_buf_data;

always @(posedge sclk)
	r_buf_addr<=r_buf_addr+'d1;
always @(posedge sclk)begin
	r_buf_addr_t<=r_buf_addr;
	r_buf_addr_tt<=r_buf_addr_t;
	end
assign	conf_addr=r_buf_addr_t;
	
mdio_wr	mdio_wr(
		.sclk(sclk),//125M
		.rst_n(rst_n),
		.w_en(w_flag),// one period valid sclk
		.r_en(r_flag),// one period valid sclk
		.phy_addr(mdio_phy_addr),//one period valid sclk
		.reg_addr(mdio_reg_addr),//one period valid sclk
		.w_data(mdio_w_data),
		.r_data(r_data) ,
		.rd_v (r_dv),
		.busy(busy),
		.mdio(mdio),
		.mdc(mdc)
);

always @(posedge sclk or negedge rst_n)
	if(rst_n=='d0)
		wr_busy<='d0;
	else if(state==IDLE)
		wr_busy<='d1;
	else if(state==READ || state==WRITE)
		wr_busy<='d0;
endmodule